package com.alogic.xscript.plugins;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import com.alogic.xscript.ExecuteWatcher;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.doc.XsObject;
import com.alogic.xscript.doc.json.JsonObject;
import com.anysoft.util.BaseException;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.jayway.jsonpath.JsonPath;

/**
 * 循环
 * 
 * @author duanyy
 * @version 1.6.7.22 [20170306 duanyy] <br>
 * - 当jsonPath语法错误或者节点不存在时，不再抛出异常 <br>
 * 
 * @version 1.6.8.4 [20170329 duanyy] <br>
 * - 对象的属性可以循环处理 <br>
 * 
 * @version 1.6.9.1 [20170516 duanyy] <br>
 * - 修复部分插件由于使用新的文档模型产生的兼容性问题 <br>
 *
 * @version 1.6.12.50 [20191202 duanyy] <br>
 * - 不再支持异步模式 <br>
 *
 * @version 1.6.13.23 [20201030 duanyy] <br>
 * - 优化xscript的日志机制  <br>
 *
 * @version 1.6.14.15 [20210802 duanyy] <br>
 * - 增加循环跳出条件 <br>
 */
public class Repeat extends Segment{
	protected String jsonPath;
	protected String value = "$value";
	protected String key = "$key";
	protected String $break = "false";

	public Repeat(String tag, Logiclet p) {
		super(tag, p);
	}

	@Override
	public void configure(Properties p){
		super.configure(p);
		jsonPath = PropertiesConstants.getString(p, "path", jsonPath,true);
		value = PropertiesConstants.getString(p,"value",value,true);
		key = PropertiesConstants.getString(p,"key",key,true);
		$break = PropertiesConstants.getRaw(p,"break",$break);
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void onExecute(XsObject root,XsObject current, LogicletContext ctx, ExecuteWatcher watcher) {
		if (current instanceof JsonObject){
			if (StringUtils.isNotEmpty(jsonPath)){
				Object result = null;
				try {
					result = JsonPath.read(current.getContent(), jsonPath);
				}catch (Exception ex){
					log("Can not read jsonpath :" + jsonPath,LOG_ERROR,ctx);
				}
				if (result != null){
					if (result instanceof List<?>){
						repeat((List<Object>)result,root,current,ctx,watcher);
					}else{
						if (result instanceof Map<?,?>){
							repeat((Map<String,Object>)result,root,current,ctx,watcher);
						}else{
							log("Can not locate the path:" + jsonPath,LOG_ERROR,ctx);
						}
					}
				}
			}
		}else{
			throw new BaseException("core.e1000",
					String.format("Tag %s does not support protocol %s",this.getXmlTag(),root.getClass().getName()));	
		}
	}

	protected void repeat(final List<Object> list,final XsObject root,final XsObject current,
			final LogicletContext ctx, final ExecuteWatcher watcher){
		for (Object o:list){
			if (o instanceof Map<?,?>){
				super.onExecute(root, new JsonObject("current",(Map<String,Object>)o), ctx, watcher);
			}else{
				ctx.SetValue(value, o.toString());
				super.onExecute(root, current, ctx, watcher);
			}
			if (PropertiesConstants.transform(ctx,$break,false)){
				break;
			}
		}
	}
	
	protected void repeat(final Map<String,Object> map,final XsObject root,final XsObject current,
			final LogicletContext ctx, final ExecuteWatcher watcher){
		Iterator<Entry<String,Object>> iter = map.entrySet().iterator();
		while (iter.hasNext()){
			Entry<String,Object> entry = iter.next();
			Object val = entry.getValue();
			if (val instanceof String || val instanceof Number){
				ctx.SetValue(key, entry.getKey());
				ctx.SetValue(value, val.toString());
				super.onExecute(root, current, ctx, watcher);
				if (PropertiesConstants.transform(ctx,$break,false)){
					break;
				}
			}
		}
	}
}
